package com.egg.auth.config.token;

import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
import cn.dev33.satoken.oauth2.model.SaClientModel;
import cn.dev33.satoken.stp.StpUtil;
import com.egg.auth.entity.Client;
import com.egg.auth.entity.user.UserAccount;
import com.egg.auth.enums.account.AccountStateEnum;
import com.egg.auth.enums.account.AccountTypeEnum;
import com.egg.auth.service.client.IClientService;
import com.egg.auth.service.user.IUserAccountService;
import com.egg.auth.utils.PasswordUtil;
import com.egg.common.core.exception.CustomException;
import com.egg.common.core.model.response.ResponseData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * Sa-Token OAuth2.0 整合实现
 */
@Configuration
public class SaOAuth2TemplateConfig extends SaOAuth2Template {


    @Autowired
    private IClientService clientService;
    @Autowired
    private IUserAccountService userAccountService;

    // 根据 id 获取 Client 信息 
    @Override
    public SaClientModel getClientModel(String clientId) {
        Client client = clientService.baseGetById(clientId);
        SaClientModel saClientModel = new SaClientModel();
        saClientModel.setClientId(client.getId().toString());
        saClientModel.setClientSecret(client.getSecret());
        saClientModel.setAllowUrl(client.getAllowUrl());
        saClientModel.setContractScope(client.getScope());
        saClientModel.setIsCode(client.getIsCode());
        saClientModel.setIsImplicit(client.getIsImplicit());
        saClientModel.setIsPassword(client.getIsPassword());
        saClientModel.setIsAutoMode(client.getIsAutoMode());
        saClientModel.setIsNewRefresh(client.getIsNewRefresh());
        saClientModel.setAccessTokenTimeout(client.getAccessTokenTimeout());
        saClientModel.setRefreshTokenTimeout(client.getRefreshTokenTimeout());
        return saClientModel;
    }

    // Sa-OAuth2 定制化配置
    @Autowired
    public void setSaOAuth2Config(SaOAuth2Config cfg) {
        // 未登录的视图
        cfg.setNotLoginView(() -> new ModelAndView("login.html"));
        //注意：在setDoLoginHandle函数里如果要获取name, pwd以外的参数，可通过SaHolder.getRequest().getParam("xxx")来获取
        // 配置：登录处理函数
        cfg.setDoLoginHandle((name, pwd) -> {
            Optional<UserAccount> userAccount = userAccountService.findByUsername(AccountTypeEnum.PASSWORD.getCode(), name);
            if (!userAccount.isPresent()
                    || !PasswordUtil.equalsPassword(pwd, userAccount.get().getPassword())
            ) {
                throw new CustomException("账号或密码错误");
            }
            if (!Objects.equals(AccountStateEnum.ENABLED.getCode(), userAccount.get().getState())) {
                throw new CustomException("账号非启用状态");
            }
            StpUtil.login(userAccount.get().getUserId());
            return ResponseData.success();
        });
        // 授权确认视图
        cfg.setConfirmView((clientId, scope) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("clientId", clientId);
            map.put("scope", scope);
            return new ModelAndView("confirm.html", map);
        });
        // 授权码
        cfg.setIsCode(true);
        // 隐藏式
        cfg.setIsImplicit(true);
        // 密码式
        cfg.setIsPassword(true);
        // 凭证式
        cfg.setIsClient(true);
    }

    // 根据ClientId 和 LoginId 获取openid 
    @Override
    public String getOpenid(String clientId, Object loginId) {
        // 此为模拟数据，真实环境需要从数据库查询 
        return clientId + "_" + loginId.toString();
    }


}